package com.example.ssyinitlearn.config;

import com.example.ssyinitlearn.authenticationProvider.MyDaoAuthenticationProvider;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.OrRequestMatcher;

import java.io.BufferedReader;
import java.util.HashMap;

@Order(2)
@Configuration
public class DoLogin_2_Config extends WebSecurityConfigurerAdapter {
    /**
     * configure 1.1
     * 多过滤器链
     * @param http
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {

        // 上面只是进入到该拦截器，但是没有说到底是放行还是有认证要求
        http.antMatcher("/test2/**")
                .authorizeRequests()
                .anyRequest().authenticated();

        // .formLogin()开启登录表单配置
        // 还有一种简单的写法，那就是直接在上面使用 .and().formLogin 以链式来进行书写
        http.formLogin()
                // 指定进行认证的登录页面
                .loginPage("/login2.html")
                // 进行登录认证处理的路径
                .loginProcessingUrl("/test2/doLogin2")
                // 直连登录页面成功后的响应地址
                .defaultSuccessUrl("/test2")
                // 登录失败之后返回哪里？
                .failureUrl("/login2.html")
                // 登录页面传递的username和password变量的名字是啥
                .usernameParameter("uname")
                .passwordParameter("passwd")
                // 与登录相关的页面和接口不做拦截，直接通过
                .permitAll();

        // 关闭CSRF防御功能。当然依然可以用 .and() 来写
        http.csrf()
                .disable();
    }

    /**
     * configure 2.1
     * 用 局部UserDetailsService 覆盖掉全局 UserDetailsService对该过滤器链的影响
     * @param auth
     * @throws Exception
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        // 自定义的的UserDetailsService
        InMemoryUserDetailsManager inMemory_login2_part = new InMemoryUserDetailsManager(){
            @Override
            public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
                if(!username.equals("inMemory_login2_part")){
                    throw new UsernameNotFoundException("inMemory_login2_part 未找到用户:" + username);
                }
                return super.loadUserByUsername(username);
            }
        };
        inMemory_login2_part.createUser(User.builder().
                username("inMemory_login2_part").
                password("{noop}123").
                roles("user").
                build());

        // 此时全局的 Provider也失效，必须手动指定使用的 Provider
        MyDaoAuthenticationProvider myDao = new MyDaoAuthenticationProvider();
        myDao.setHideUserNotFoundExceptions(false);
        myDao.setUserDetailsService(inMemory_login2_part);
        auth.authenticationProvider(myDao);
    }

}
